# app/logger_setup.py

from dataclasses import dataclass
import logging
import os
from logging.handlers import TimedRotatingFileHandler, RotatingFileHandler
from typing import Optional, Dict
from pathlib import Path
import sys
import traceback

@dataclass
class LogConfig:
    """日志配置数据类"""
    log_file: str
    log_level: int
    backup_count: int
    log_to_console: bool
    max_bytes: int = 10 * 1024 * 1024  # 默认10MB
    encoding: str = 'utf-8'
    
class LoggerFactory:
    """日志工厂类，负责创建和配置日志器"""
    
    _loggers: Dict[str, logging.Logger] = {}  # 缓存已创建的日志器
    
    @staticmethod
    def create_formatter(detailed: bool = True) -> logging.Formatter:
        """
        创建日志格式化器
        
        Args:
            detailed: 是否使用详细格式
            
        Returns:
            logging.Formatter: 配置好的格式化器
        """
        if detailed:
            return logging.Formatter(
                fmt='%(asctime)s.%(msecs)03d - %(levelname)s - [%(process)d:%(thread)d] - '
                    '%(filename)s:%(lineno)d - %(funcName)s() - %(message)s',
                datefmt='%Y-%m-%d %H:%M:%S'
            )
        else:
            return logging.Formatter(
                fmt='%(asctime)s - %(levelname)s - %(message)s',
                datefmt='%Y-%m-%d %H:%M:%S'
            )
    
    @classmethod
    def get_logger(cls, name: str) -> logging.Logger:
        """
        获取或创建日志器（单例模式）
        
        Args:
            name: 日志器名称
            
        Returns:
            logging.Logger: 日志器实例
        """
        if name not in cls._loggers:
            cls._loggers[name] = logging.getLogger(name)
        return cls._loggers[name]

class LoggerSetup:
    """日志系统配置类"""
    
    def __init__(self, config: LogConfig):
        """
        初始化日志设置
        
        Args:
            config: LogConfig 实例，包含所有日志配置
            
        Raises:
            RuntimeError: 当日志目录创建失败或处理器创建失败时
        """
        self.config = config
        self._ensure_log_directory()
        
    def _ensure_log_directory(self) -> None:
        """
        确保日志目录存在
        
        Raises:
            RuntimeError: 当目录创建失败时
        """
        log_dir = Path(self.config.log_file).parent
        try:
            log_dir.mkdir(parents=True, exist_ok=True)
            self._check_directory_permissions(log_dir)
        except Exception as e:
            error_msg = f"Failed to create log directory {log_dir}: {e}"
            self._handle_critical_error(error_msg)

    def _check_directory_permissions(self, directory: Path) -> None:
        """
        检查目录权限
        
        Args:
            directory: 目录路径
            
        Raises:
            RuntimeError: 当目录权限不足时
        """
        if not os.access(directory, os.W_OK):
            error_msg = f"No write permission for log directory: {directory}"
            self._handle_critical_error(error_msg)

    def _create_file_handler(self) -> TimedRotatingFileHandler:
        """
        创建文件日志处理器
        
        Returns:
            TimedRotatingFileHandler: 配置好的文件处理器
            
        Raises:
            RuntimeError: 当处理器创建失败时
        """
        try:
            handler = TimedRotatingFileHandler(
                filename=self.config.log_file,
                when="midnight",
                interval=1,
                backupCount=self.config.backup_count,
                encoding=self.config.encoding
            )
            handler.setFormatter(LoggerFactory.create_formatter())
            return handler
        except Exception as e:
            error_msg = f"Failed to create file handler: {e}"
            self._handle_critical_error(error_msg)

    def _create_console_handler(self) -> logging.StreamHandler:
        """
        创建控制台日志处理器
        
        Returns:
            logging.StreamHandler: 配置好的控制台处理器
        """
        handler = logging.StreamHandler(sys.stdout)
        handler.setFormatter(LoggerFactory.create_formatter(detailed=False))
        return handler

    def _handle_critical_error(self, error_msg: str) -> None:
        """
        处理关键错误
        
        Args:
            error_msg: 错误信息
            
        Raises:
            RuntimeError: 始终抛出运行时错误
        """
        print(f"Critical Error: {error_msg}", file=sys.stderr)
        print("Traceback:", file=sys.stderr)
        traceback.print_exc(file=sys.stderr)
        raise RuntimeError(error_msg)

    def get_logger(self, name: Optional[str] = None) -> logging.Logger:
        """
        获取配置好的日志器
        
        Args:
            name: 日志器名称，默认为root日志器
            
        Returns:
            logging.Logger: 配置好的日志器实例
            
        Raises:
            RuntimeError: 当日志器初始化失败时
        """
        logger = LoggerFactory.get_logger(name if name else '')
        
        # 避免重复配置
        if logger.handlers:
            return logger
            
        try:
            logger.setLevel(self.config.log_level)
            
            # 添加文件处理器
            file_handler = self._create_file_handler()
            logger.addHandler(file_handler)
            
            # 添加控制台处理器（如果配置允许）
            if self.config.log_to_console:
                console_handler = self._create_console_handler()
                logger.addHandler(console_handler)
            
            logger.propagate = False
            
            # 记录日志器初始化信息
            logger.info(
                f"Logger initialized: name='{name if name else 'root'}', "
                f"level={logging.getLevelName(self.config.log_level)}, "
                f"file={self.config.log_file}"
            )
            
            return logger
            
        except Exception as e:
            error_msg = f"Failed to initialize logger: {e}"
            self._handle_critical_error(error_msg)

    def initialize_logger(self) -> logging.Logger:
        """
        初始化并返回root日志器
        
        Returns:
            logging.Logger: root日志器实例
        """
        return self.get_logger()
    